package com.sunsoft.sample.concurrent;
import java.util.concurrent.Semaphore;

import net.jcip.annotations.GuardedBy;
import net.jcip.annotations.ThreadSafe;

@ThreadSafe
public class BoundedBuffer<E> {

	private final Semaphore avaliableItems,avaliableSpaces;
	@GuardedBy("this")private final E[] items;
	@GuardedBy("this")private int putPosition = 0, takePosition = 0;
	
	public BoundedBuffer(int capacity){
		avaliableItems = new Semaphore(0);
		avaliableSpaces = new Semaphore(capacity);
		items = (E[]) new Object[capacity];
	}
	
	public boolean isEmpty(){
		return avaliableItems.availablePermits() == 0;
	}
	
	public boolean isFull(){
		return avaliableSpaces.availablePermits() == 0;
	}
	
	public void put(E x)throws InterruptedException {
		avaliableSpaces.acquire();
		doInsert(x);
		avaliableItems.release();
	}
	
	public E take()throws InterruptedException {
		avaliableItems.acquire();
		E item = doExtract();
		avaliableSpaces.release();
		return item;
	}
	
	private synchronized void doInsert(E x){
		int i = putPosition;
		items[i] = x;
		putPosition = (++i == items.length) ? 0: i;
	}
	
	private synchronized E doExtract() {
		int i = takePosition;
		E x = items[i];
		items[i] = null;
		takePosition = (++i == items.length) ? 0 : i;
		return x;
	}
}
